Android广播按发送方式分类有三种:无序广播、有序广播(OrderedBroadcast)和粘性广播(StickyBroadcast)。
静态广播的注册流程:
在系统服务启动时会添加PackageManagerService,在该类的构造方法中就会对各个应用安装目录的apk文件进行扫描解析。先看下时序图:
先看PackageManagerService类的构造方法:
// Keys are String (package name), values are Package. This also serves
// as the lock for the global state. Methods that must be called with
// this lock held have the prefix "LP".
@GuardedBy("mPackages")// 域注解:是对类里面成员变量加的注解.受与mPackages引用相关联的锁保护
final ArrayMap<String, PackageParser.Package> mPackages =
new ArrayMap<String, PackageParser.Package>();
public PackageManagerService(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
. . .
// Collect ordinary system packages.
final File systemAppDir = new File(Environment.getRootDirectory(),
"app");
scanDirLI(systemAppDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
// 扫描其他路径
. . .
}
private void scanDirLI(File dir, int parseFlags, int scanFlags, long currentTime) {
final File[] files = dir.listFiles();
if (ArrayUtils.isEmpty(files)) {
Log.d(TAG, "No files in app dir " + dir);
return;
}
if (DEBUG_PACKAGE_SCANNING) {
Log.d(TAG, "Scanning app dir " + dir + " scanFlags=" + scanFlags
+ " flags=0x" + Integer.toHexString(parseFlags));
}
Log.d(TAG, "start scanDirLI:"+dir);
// use multi thread to speed up scanning
int iMultitaskNum = SystemProperties.getInt("persist.pm.multitask", 6);
Log.d(TAG, "max thread:" + iMultitaskNum);
final MultiTaskDealer dealer = (iMultitaskNum > 1) ? MultiTaskDealer.startDealer(
MultiTaskDealer.PACKAGEMANAGER_SCANER, iMultitaskNum) : null;
for (File file : files) {
final boolean isPackage = (isApkFile(file) || file.isDirectory())
&& !PackageInstallerService.isStageName(file.getName());
if (!isPackage) {
// Ignore entries which are not packages
continue;
}
if (RegionalizationEnvironment.isSupported()) {
if (RegionalizationEnvironment.isExcludedApp(file.getName())) {
Slog.d(TAG, "Regionalization Excluded:" + file.getName());
continue;
}
}
final File ref_file = file;
final int ref_parseFlags = parseFlags;
final int ref_scanFlags = scanFlags;
final long ref_currentTime = currentTime;
Runnable scanTask = new Runnable() {
public void run() {
try {
// 扫描文件
scanPackageLI(ref_file, ref_parseFlags | PackageParser.PARSE_MUST_BE_APK,
ref_scanFlags, ref_currentTime, null);
} catch (PackageManagerException e) {
Slog.w(TAG, "Failed to parse " + ref_file + ": " + e.getMessage());
// Delete invalid userdata apps
if ((ref_parseFlags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
e.error == PackageManager.INSTALL_FAILED_INVALID_APK) {
logCriticalInfo(Log.WARN, "Deleting invalid package at " + ref_file);
if (ref_file.isDirectory()) {
mInstaller.rmPackageDir(ref_file.getAbsolutePath());
} else {
ref_file.delete();
}
}
}
}
};
if (dealer != null)
dealer.addTask(scanTask);
else
scanTask.run();
}
if (dealer != null)
dealer.waitAll();
Log.d(TAG, "end scanDirLI:"+dir);
}
/*
* Scan a package and return the newly parsed package.
* Returns null in case of errors and the error code is stored in mLastScanError
*/
private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,
long currentTime, UserHandle user) throws PackageManagerException {
if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile);
parseFlags |= mDefParseFlags;
PackageParser pp = new PackageParser();
pp.setSeparateProcesses(mSeparateProcesses);
pp.setOnlyCoreApps(mOnlyCore);
pp.setDisplayMetrics(mMetrics);
if ((scanFlags & SCAN_TRUSTED_OVERLAY) != 0) {
parseFlags |= PackageParser.PARSE_TRUSTED_OVERLAY;
}
final PackageParser.Package pkg;
try {
// 根据文件路径解析文件
pkg = pp.parsePackage(scanFile, parseFlags);
} catch (PackageParserException e) {
throw PackageManagerException.from(e);
}
. . .
// Note that we invoke the following method only if we are about to unpack an application
PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanFlags
| SCAN_UPDATE_SIGNATURE, currentTime, user);
. . .
return scannedPkg;
}
上面scanPackageLI方法中主要执行两个方法:PackageParser类中的parsePackage方法和PackageManagerService类中的scanPackageLI重载方法,这里按顺序看,先看parsePackage方法:
/** File name in an APK for the Android manifest. */
private static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml";
/** Path prefix for apps on expanded storage */
private static final String MNT_EXPAND = "/mnt/expand/";
/**
* Parse the package at the given location. Automatically detects if the
* package is a monolithic style (single APK file) or cluster style
* (directory of APKs).
*/
public Package parsePackage(File packageFile, int flags) throws PackageParserException {
if (packageFile.isDirectory()) {
// 解析文件夹下所有apk文件
return parseClusterPackage(packageFile, flags);
} else {
// 解析apk文件
return parseMonolithicPackage(packageFile, flags);
}
}
/**
* Parse all APKs contained in the given directory, treating them as a
* single package. This also performs sanity checking, such as requiring
* identical package name and version codes, a single base APK, and unique
* split names.
*/
private Package parseClusterPackage(File packageDir, int flags) throws PackageParserException {
// 解析文件夹下所有apk文件的基本信息
final PackageLite lite = parseClusterPackageLite(packageDir, 0);
if (mOnlyCoreApps && !lite.coreApp) {
throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
"Not a coreApp: " + packageDir);
}
final AssetManager assets = new AssetManager(